using System;
using System.IO;
using System.Data;
using System.Configuration;
using System.Web;
//using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using Microsoft.Reporting.WebForms;
using System.Collections.Generic;
using System.Drawing.Imaging;
using System.Drawing.Printing;
using System.Text;

namespace OmcfBRL
{
   public class ReportViewerManager : IDisposable
   {

      protected const String c_strExceptionMessageFormat = "(Class ReportViewerManager) In {0}: {1}";
      protected const String c_strReportMissingMessage = "(Class ReportViewerManager) The ReportName property has not been initialized";
      protected const String c_strDestinationFileMissingMessage = "(Class ReportViewerManager) Destination file name cannot be null or empty";
      protected const String c_strDeviceInfoStringFormat = "<DeviceInfo><OutputFormat>{0}</OutputFormat><StartPage>{1}</StartPage></DeviceInfo>";

      protected ReportViewer m_rv;
      protected ReportExportType m_rext = ReportExportType.Pdf;

      protected String m_strPrinter;
      protected String m_strPageWidth;
      protected String m_strPageHeight;

      protected String m_strMarginLeft;
      protected String m_strMarginRight;
      protected String m_strMarginTop;
      protected String m_strMarginBotton;


      public ReportExportType ExportType
      {
         get { return m_rext; }
         set { m_rext = value; }
      }

      public LocalReport LocalReport
      {
         get { return m_rv.LocalReport; }
      }

      public String PrinterName
      {
          get { return m_strPrinter; }
          set { m_strPrinter = value; }
      }

      public String PageWidth
      {
          get { return m_strPageWidth; }
          set { m_strPageWidth = value; }
      }
      public String PageHeight
      {
          get { return m_strPageHeight; }
          set { m_strPageHeight = value; }
      }

      public String MarginLeft
      {
          get { return m_strMarginLeft ; }
          set { m_strMarginLeft = value; }
      }
      public String MarginRight
      {
          get { return m_strMarginRight; }
          set { m_strMarginRight = value; }
      }

      public String MarginTop
      {
          get { return m_strMarginTop ; }
          set { m_strMarginTop = value; }
      }
      public String MarginBotton
      {
          get { return m_strMarginBotton; }
          set { m_strMarginBotton = value; }
      }
      
       public ReportViewerManager(String strReportPath)
      {
          m_rv = new ReportViewer();
          m_rv.ReportError += new ReportErrorEventHandler(ReportViewer_ReportError);
          m_rv.LocalReport.ReportPath = strReportPath;
      }

      public ReportViewerManager(String strReportPath, ReportDataSource rds)
      {
         m_rv = new ReportViewer();
         m_rv.ReportError += new ReportErrorEventHandler(ReportViewer_ReportError);
         m_rv.LocalReport.DataSources.Add(rds);
         m_rv.LocalReport.ReportPath = strReportPath;
      }

      public ReportViewerManager(String strReportPath, ReportDataSource[] arrayRds)
      {
         if (arrayRds == null)
            throw new Exception("(ReportViewerManager) In constructor: the second parameter cannot be null!");
         m_rv = new ReportViewer();
         m_rv.ReportError += new ReportErrorEventHandler(ReportViewer_ReportError);
         for (Int32 i = 0; i < arrayRds.Length; i++)
            m_rv.LocalReport.DataSources.Add(arrayRds[i]);
         m_rv.LocalReport.ReportPath = strReportPath;
      }

      void ReportViewer_ReportError(object sender, ReportErrorEventArgs e)
      {
      }

      public void ExportToFile(String strDestinationFileName)
      {
         if (m_rv.LocalReport.ReportPath == null || m_rv.LocalReport.ReportPath == String.Empty)
            throw new Exception(c_strReportMissingMessage);
         if (strDestinationFileName == null || strDestinationFileName == String.Empty)
            throw new Exception(c_strDestinationFileMissingMessage);
         try
         {
            Warning[] arWngs = null;
            String[] arStrStreamIds = null;
            String strEncoding, strMimeType, strFileNameExtension;
            String strDeviceInfo = String.Format(c_strDeviceInfoStringFormat, m_rext.ToString(), 0);

            Byte[] arByteResult = m_rv.LocalReport.Render(m_rext.ToString(), strDeviceInfo, out strMimeType, out strEncoding, out strFileNameExtension, out arStrStreamIds, out arWngs);
            FileStream fs = File.Create(strDestinationFileName, arByteResult.Length);

            fs.Write(arByteResult, 0, arByteResult.Length);
            fs.Close();
         }
         catch (Exception ex)
         {
            String strError = String.Empty;
            Exception e = ex;
            while (e.InnerException != null)
            {
               strError += "Inner {" + e.InnerException.Message + "} ";
               e = e.InnerException;
            }
            throw new Exception(String.Format(c_strExceptionMessageFormat, "In ExportToFile", "File " + strDestinationFileName + "::" + strError + ex.Message));
         }
      }

      public void ExportToStream(Stream streamOut)
      {
         if (m_rv.LocalReport.ReportPath == null || m_rv.LocalReport.ReportPath == String.Empty)
            throw new Exception(c_strReportMissingMessage);
         try
         {
            String strDeviceInfo = String.Format(c_strDeviceInfoStringFormat, m_rext.ToString().ToUpper(), 0);
            String strEncoding, strMimeType, strFileNameExtension;
            String[] arStrStreamIds = null;
            Warning[] arWngs = null;

            Byte[] arByteResult = m_rv.LocalReport.Render(m_rext.ToString(), strDeviceInfo, out strMimeType, out strEncoding, out strFileNameExtension, out arStrStreamIds, out arWngs);
            streamOut.Write(arByteResult, 0, arByteResult.Length);
            streamOut.Flush();
            streamOut.Close();
         }
         catch (Exception ex)
         {
            throw new Exception(String.Format(c_strExceptionMessageFormat, "In ExportToStream", ex.Message));
         }
      }

      public Byte[][] Render()
      {
         if (m_rv.LocalReport.ReportPath == null || m_rv.LocalReport.ReportPath == String.Empty)
            throw new Exception(c_strReportMissingMessage);
         try
         {
            String strDeviceInfo = String.Format(c_strDeviceInfoStringFormat, m_rext.ToString().ToUpper(), 0);
            String strEncoding, strMimeType, strFileNameExtension;
            String[] arStrStreamIds = null;
            Warning[] arWngs = null;

            Byte[] arByteFirstPage = m_rv.LocalReport.Render(m_rext.ToString(), strDeviceInfo, out strMimeType, out strEncoding, out strFileNameExtension, out arStrStreamIds, out arWngs);

            Int32 iNumberOfPages = arStrStreamIds.Length + 1;
            Byte[][] arBytePages = new Byte[iNumberOfPages][];

            arBytePages[0] = arByteFirstPage;

            for (Int32 iPageIndex = 1; iPageIndex < iNumberOfPages; iPageIndex++)
            {
               strDeviceInfo = String.Format(c_strDeviceInfoStringFormat, m_rext.ToString().ToUpper(), iPageIndex);
               arBytePages[iPageIndex] = m_rv.LocalReport.Render(m_rext.ToString(), strDeviceInfo, out strMimeType, out strEncoding, out strFileNameExtension, out arStrStreamIds, out arWngs);
            }
            return arBytePages;
         }
         catch (Exception ex)
         {
            throw new Exception(String.Format(c_strExceptionMessageFormat, "In ExportToStream", ex.Message));
         }
      }

      private int m_currentPageIndex;
      private IList<Stream> m_streams;

      private Stream CreateStreams(string name, string fileNameExtension, Encoding encoding, string mimeType, bool willSeek)
      {
          Stream stream = new MemoryStream();
          m_streams.Add(stream);
          return stream;
      }
      private void Export(LocalReport report)
      {
          string deviceInfo = "<DeviceInfo> <OutputFormat>EMF</OutputFormat><PageWidth>" + m_strPageWidth + "</PageWidth><PageHeight>" + m_strPageHeight + "</PageHeight> <MarginTop>" + m_strMarginTop + "</MarginTop> <MarginLeft>" + m_strMarginLeft + "</MarginLeft>  <MarginRight>" + m_strMarginRight + "</MarginRight>  <MarginBottom>" + m_strMarginBotton  + "</MarginBottom></DeviceInfo>";
          //string deviceInfo = "<DeviceInfo> <OutputFormat>EMF</OutputFormat></DeviceInfo>";
          Warning[] warnings;
          m_streams = new List<Stream>();
          report.Render("Image", deviceInfo, CreateStreams, out warnings);
          foreach (Stream stream in m_streams)
              stream.Position = 0;
      }
      private void PrintPage(object sender, PrintPageEventArgs ev)
      {

          Metafile pageImage = new Metafile(m_streams[m_currentPageIndex]);
          ev.Graphics.DrawImage(pageImage,0, 0);
          m_currentPageIndex++;
          ev.HasMorePages = (m_currentPageIndex < m_streams.Count);

      }
      private void Print()
      {
        
          if (m_streams == null || m_streams.Count == 0)
              return;

          PrintDocument printDoc = new PrintDocument();
          printDoc.PrinterSettings.PrinterName = m_strPrinter;
          printDoc.PrintPage += new PrintPageEventHandler(PrintPage);
          printDoc.Print();
      }

      public void ExportAndPrint()
      {
          if (m_rv.LocalReport.ReportPath == null || m_rv.LocalReport.ReportPath == String.Empty)
              throw new Exception(c_strReportMissingMessage);
          Export(m_rv.LocalReport);
          m_currentPageIndex = 0;
          Print();

      }



      #region IDisposable Members

      public void Dispose()
      {
         m_rv.Dispose();
      }

      #endregion
   }

   public enum ReportExportType
   {
      Pdf = 0,
      Excel = 1 
   }
}